/**
 * vim: set ts=4 :
 * =============================================================================
 * ServerTools
 * Copyright (C) 2012 DonRevan.  All rights reserved.
 * =============================================================================
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, version 3.0, as published by the
 * Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "extension.h"
#include "icvar.h"

ServerTools g_Extension;
SMEXT_LINK(&g_Extension);

ISDKTools *g_pSDKTools = NULL;
IServer *server = NULL;
//IForward *forward_GetMaxClients = NULL;
ICvar *icvar = NULL;

// Declare the Hooks
SH_DECL_HOOK0(IServer, GetMaxClients, const, 0, int);

cell_t Native_SetPause(IPluginContext *pContext, const cell_t *params);
cell_t Native_GetPause(IPluginContext *pContext, const cell_t *params);
cell_t Native_CanPause(IPluginContext *pContext, const cell_t *params);
cell_t Native_DisguisedKick(IPluginContext *pContext, const cell_t *params);
sp_nativeinfo_t g_Natives[] = 
{
	{"SetPause",				Native_SetPause},
	{"IsPaused",				Native_GetPause},
	{"IsPausable",				Native_GetPause},
	{"ForceDisconnect",			Native_DisguisedKick},
	{NULL,						NULL}
};

// ConVar shim
class BaseAccessor : public IConCommandBaseAccessor
{
public:
	bool RegisterConCommandBase(ConCommandBase *pCommandBase)
	{
		/* Always call META_REGCVAR instead of going through the engine. */
		return META_REGCVAR(pCommandBase);
	}
} s_BaseAccessor;

// ConVar Change hook
static void Hook_SlotsChanged(IConVar *var, const char *pOldValue, float flOldValue)
{
	g_Extension.iFakeSlots = static_cast<ConVar*>(var)->GetInt();
}

ConVar cvar_fakeslots("sm_fakeslots", "0", FCVAR_PLUGIN, "Amount of reported slots", true, 0.0, true, 64.0, Hook_SlotsChanged);

bool ServerTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
	// We'll only run fine if sdktools is available
	sharesys->AddDependency(myself, "sdktools.ext", true, true);
	// Add the natives
	sharesys->AddNatives(myself, g_Natives);
	// Register our forwards
	//forward_GetMaxClients = forwards->CreateForward("OnGetMaxClients", ET_Ignore, 3, NULL, Param_Cell, Param_Cell, Param_CellByRef);
	return true;
}

bool ServerTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
{
	// More ConVar shim
	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
	g_pCVar = icvar;
	ConVar_Register(0, &s_BaseAccessor);
	return true;
}

void ServerTools::SDK_OnUnload()
{
	// If we obtained a valid IServer pointer we can safetly shut down our hooks
	if(server) {
		SH_REMOVE_HOOK_MEMFUNC(IServer, GetMaxClients, server, &g_Extension, &ServerTools::Hook_GetMaxClients, true);
	}
}

void ServerTools::SDK_OnAllLoaded()
{
	// We'd need to get SDKTools interface to be able to retrieve the IServer pointer
	SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
	if( !g_pSDKTools ) {
		g_pSM->LogError(myself,"Could not fetch SDKTools interface!");
		return;
	}
	// Get a pointer to IServer
	server = g_pSDKTools->GetIServer();
	if( !server ) {
		g_pSM->LogError(myself,"Could not get valid pointer to IServer!");
		return;
	}
	// Hook all the stuff we need
	SH_ADD_HOOK_MEMFUNC(IServer, GetMaxClients, server, &g_Extension, &ServerTools::Hook_GetMaxClients, true);
}

int ServerTools::Hook_GetMaxClients()
{
	if( iFakeSlots > 0 ) {
		RETURN_META_VALUE(MRES_SUPERCEDE, iFakeSlots);
	}
	RETURN_META_VALUE(MRES_SUPERCEDE, META_RESULT_ORIG_RET(int));
}

cell_t Native_SetPause(IPluginContext *pContext, const cell_t *params)
{
	if( !server ) {
		return pContext->ThrowNativeError("Could not get valid pointer to IServer!");
	}
	server->SetPaused( ( bool )params[1] );
	return 1;
}

cell_t Native_GetPause(IPluginContext *pContext, const cell_t *params)
{
	if( !server ) {
		return pContext->ThrowNativeError("Could not get valid pointer to IServer!");
	}
	return server->IsPaused();
}

cell_t Native_CanPause(IPluginContext *pContext, const cell_t *params)
{
	if( !server ) {
		return pContext->ThrowNativeError("Could not get valid pointer to IServer!");
	}
	return server->IsPausable();
}

cell_t Native_DisguisedKick(IPluginContext *pContext, const cell_t *params)
{
	if( !server ) {
		return pContext->ThrowNativeError("Could not get valid pointer to IServer!");
	}
	IClient *pClient = server->GetClient(params[1]);
	char *buffer;
	pContext->LocalToString(params[2], &buffer);
	server->DisconnectClient( pClient, buffer);
	return 1;
}